package Robots;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Stack;
import java.awt.Rectangle;

import javax.swing.ImageIcon;














import Linguo.Mapa;
import Objetos.Blanca;
import Objetos.Coleccionable;
import Objetos.Elemento;
import Objetos.Intransitable;
import Objetos.Negro;
import Objetos.Pintura;
import Objetos.Premio;
import Objetos.Transitable;


/**
 * Clase Robot
 * @author Andres Garcia Amado, Federico Quattrocchio, Marias Lameiro.
 */
public abstract class Robot extends Elemento{

	/** The ii_ s. */
	protected ImageIcon ii_S;

	/** The ii_ e. */
	protected ImageIcon ii_E;

	/** The ii_ o. */
	protected ImageIcon ii_O;

	/** The ii. */
	protected ImageIcon ii;

	/** El baul que contiene los items Coleccionables que junto el robot.*/
	protected Stack<Coleccionable> baul;

	/** Indica si el brazo del robot esta ocupado o no */
	protected boolean brazoOcupado;

	/** El Coleccionable en el brazo del robot */
	protected Coleccionable itemEnBrazo;

	/** Indica si el pincel del robot esta activado */
	protected boolean pincel;

	/** Indica del colo del pincel del robot */
	protected String color;

	/** Cantidad de nafta del robot */
	protected int nafta;

	/** Velocidad del robot */
	protected final int speed = 5;

	/** Direccion hacia la cual apunta el robot (s = sur, n = norte, o = oeste, e = este) */
	protected char direccion;

	/** Mapa sobre el cual se mueve el robot */
	protected Mapa mapa;

	/** Indica si el robot puede avanzar */
	protected boolean puedeAvanzar = true;




	/** Tamaño del robot */
	protected final int ROBOT_SIZE = 20;

	/**
	 * Constructor de la clase Robot
	 *
	 * @param x la coordenada x del robot.
	 * @param y la coordenada y del robot.
	 * @param mapa el mapa sobre el cual se movera el robot.
	 */
	public Robot(int x, int y,Mapa mapa) {

		super(x, y);
		baul= new Stack<Coleccionable>();
		itemEnBrazo = null;
		this.mapa=mapa;
		color = "negro";

	}

	/**
	 * Mueve el robot hacia adelante (si es posible) gastando nafta segun corresponda (1 si se mueve sobre asfalto, 2 si se mueve sobre arena)
	 */
	public void move() {
		Rectangle r4 = getBounds();
		boolean meMovi=true;
		ArrayList<Intransitable> it= mapa.getIntransitables();
		ArrayList<Premio> premios= mapa.getPremios();
		ArrayList<Transitable> trans= mapa.getTransitables();
		int costo=0;

		for(Transitable t: trans) {
			Rectangle r2= t.getBounds();
			if((r4.getY()+9>=r2.getY()) && (r4.getY()+9<=r2.getY()+ROBOT_SIZE) && ((r4.getX()+9>=r2.getX()) && (r4.getX()+9<=r2.getX()+ROBOT_SIZE)))
			{   
				costo=t.costoDeTransitar();
				//System.out.println("costo: "+costo);
				break;
			}
		}

		if (nafta >= costo){
			if(direccion == 's') {
				setY(getY()+speed);
				Rectangle r1 = this.getBounds();

				for(Intransitable i : it) {
					Rectangle r2 = i.getBounds();

					if (r1.intersects(r2)) {
						setY(getY()-speed);
						meMovi=false;
						break;
					}
				}

			}

			if(direccion == 'n') {
				setY(getY()-speed);
				Rectangle r1 = this.getBounds();

				for(Intransitable i : it) {
					Rectangle r2 = i.getBounds();

					if (r1.intersects(r2)) {
						setY(getY()+speed);
						meMovi=false;
						break;
					}
				}

			}

			if(direccion == 'e') {
				setX(getX()+speed);
				Rectangle r1 = this.getBounds();

				for(Intransitable i : it) {
					Rectangle r2 = i.getBounds();

					if (r1.intersects(r2)) {
						setX(getX()-speed);
						meMovi=false;
						break;
					}
				}

			}

			if(direccion == 'o') {
				setX(getX()-speed);
				Rectangle r1 = this.getBounds();

				for(Intransitable i : it) {
					Rectangle r2 = i.getBounds();

					if (r1.intersects(r2)) {
						setX(getX()+speed);
						meMovi=false;
						break;
					}
				}

			}

			if(meMovi){
				nafta-= costo;
				if (pincel){
					Pintura pin = null;
					if(color=="negro") {
						pin = new Negro(getX(),getY(),true);
					}
					else {
						pin = new Blanca(getX(),getY(),true);
					}
					if(direccion == 'n') {
						pin.setY(getY()+15);
					} else if(direccion == 'e') {
						pin.setHorizontal(false);
					} else if(direccion == 'o') {
						pin.setX(getX()+15);
						pin.setHorizontal(false);
					}

					mapa.agregarPintura(pin);
				}
			}

			Rectangle r3 = this.getBounds();
			for (Premio p: premios){
				Rectangle r2=p.getBounds();
				if(r3.intersects(r2)) {
					p.accion(this);
					p.setVisible(false);
				}
			}

		}
		else {
			puedeAvanzar = false;
		}


	}

	/**
	 * Genera un disparo.
	 */
	public abstract void fire();

	/* (non-Javadoc)
	 * @see Linguo.Elemento#getBounds()
	 */
	public Rectangle getBounds() {
		return new Rectangle(getX(), getY(), getWidth(), getHeight());
	}

	/**
	 * Setea la direccion hacia la cual apunta el robot.
	 *
	 * @param d la nueva direccion.
	 */
	public void setDireccion(char d) {
		direccion = d;
	}

	/**
	 * Devuelve la direccion hacia la cual esta apunta el robot.
	 *
	 * @return la direccion.
	 */
	public char getDireccion() {
		return direccion;
	}

	/**
	 * Agrega 50 puntos al puntaje del jugador.
	 */
	public void agregarPuntos(){
		mapa.setPuntaje(mapa.getPuntaje()+50);
	}

	/**
	 * Agrega nafta al robot.
	 */
	public abstract void agregarNafta();

	/**
	 * Agrega balas al robot.
	 */
	public abstract void agregarBalas();

	/**
	 * Hace girar el robot hacia su derecha.
	 */
	public void girarDerecha(){
		ArrayList<Transitable> trans= mapa.getTransitables();
		int costo=0;
		Rectangle r4= getBounds();

		for(Transitable t: trans){
			Rectangle r2= t.getBounds();
			if((r4.getY()+9>=r2.getY()) && (r4.getY()+9<=r2.getY()+ROBOT_SIZE) && ((r4.getX()+9>=r2.getX()) && (r4.getX()+9<=r2.getX()+ROBOT_SIZE)))
			{   
				costo=t.costoDeTransitar();
				//System.out.println("costo: "+costo);
				break;
			}
		}

		if (costo<= nafta){
			if (getDireccion() == 's') {
				this.setImage(ii_O.getImage());
				setDireccion('o');
			}

			else if (getDireccion() == 'e') {
				this.setImage(ii_S.getImage());
				setDireccion('s');
			}

			else if (getDireccion() == 'n') {
				this.setImage(ii_E.getImage());
				setDireccion('e');
			}

			else if (getDireccion() == 'o') {
				this.setImage(ii.getImage());
				setDireccion('n');
			}
			//System.out.println("Direccion del robot: "+getDireccion());
			nafta-= costo;
			//System.out.println("NaSta: "+nafta);
		}
		else {
			puedeAvanzar = false;
		}
	} 

	/**
	 * Hace girar el robot hacia su izquierda.
	 */
	public void girarIzquierda(){
		ArrayList<Transitable> trans= mapa.getTransitables();
		int costo=0;
		Rectangle r4= getBounds();

		for(Transitable t: trans){
			Rectangle r2= t.getBounds();
			if((r4.getY()+9>=r2.getY()) && (r4.getY()+9<=r2.getY()+ROBOT_SIZE) && ((r4.getX()+9>=r2.getX()) && (r4.getX()+9<=r2.getX()+ROBOT_SIZE)))
			{   
				costo=t.costoDeTransitar();
				//System.out.println("costo: "+costo);
				break;
			}
		}
		if (nafta>=costo){
			if (getDireccion() == 's') {
				this.setImage(ii_E.getImage());
				setDireccion('e');
			}

			else if (getDireccion() == 'e') {
				this.setImage(ii.getImage());
				setDireccion('n');
			}

			else if (getDireccion() == 'n') {
				this.setImage(ii_O.getImage());
				setDireccion('o');
			}

			else if (getDireccion() == 'o') {
				this.setImage(ii_S.getImage());
				setDireccion('s');
			}
			//System.out.println("Direccion del robot: "+getDireccion());
			nafta-=costo;
		}
		else {
			puedeAvanzar = false;
		}
	}

	/**
	 * Levanta (si existe) el coleccionable detras del robot y lo pone en su brazo.
	 */
	public void agarrar() {
		if(!brazoOcupado){
			for(Coleccionable c: mapa.getColeccionables()){
				if(direccion=='s'){
					if(c.getY()<=getY() && c.getY()>=getY()-20 && c.getX()==getX()){
						itemEnBrazo=c;
						brazoOcupado=true;
						c.setVisible(false);
						break;
					}
				}
				else if(direccion=='n'){
					if(c.getY()>=getY() && c.getY()-20<=getY() && c.getX()==getX()){
						itemEnBrazo=c;
						brazoOcupado=true;
						c.setVisible(false);
						break;
					}
				}
				else if(direccion=='e'){
					if(c.getX()<=getX()&& c.getX()>=getX()-20 && c.getY()==getY()){
						itemEnBrazo=c;
						brazoOcupado=true;
						c.setVisible(false);
						break;
					}
				}
				else {
					if(c.getX()>=getX()&& c.getX()-20<=getX() && c.getY()==getY()){
						itemEnBrazo=c;
						brazoOcupado=true;
						c.setVisible(false);
						break;
					}
				}
			}
		}
	}

	/**
	 * Guarda el item que se encuentra en el brazo del robot en su baul.
	 */
	public void guardarBaul(){
		if(itemEnBrazo!=null) {
			if(brazoOcupado) {
				baul.push(itemEnBrazo);
				brazoOcupado=false;
				itemEnBrazo=null;
			}
		}
	}

	/**
	 * Deja el item en el brazo del robot en el suelo.
	 */
	public void dejarItem(){
		if(brazoOcupado){
			Coleccionable c= itemEnBrazo;
			c.setVisible(true);			
			itemEnBrazo=null;
			c.setX(getX());
			c.setY(getY());
			mapa.agregarColeccionable(c);
			brazoOcupado= false;
		}
	}

	/**
	 * Consulta la cantidad de nafta que posee el robot
	 *
	 * @return la nafta del robot
	 */
	public int getNafta() {
		return nafta;
	}

	/**
	 * Consulta el item que posee el robot en el brazo
	 *
	 * @return el item en el brazo del robot. Null si no posee ningun item.
	 */
	public Coleccionable getItemEnBrazo() {
		return itemEnBrazo;
	}

	/**
	 * Consulta si el robot puede avanzar.
	 *
	 * @return true, si puede avanzar, false en caso contrario.
	 */
	public boolean puedeAvanzar() {
		return puedeAvanzar;
	}

	/**
	 * Consulta la cantidad de balas que tiene el robot.
	 *
	 * @return cantidad de balas.
	 */
	public abstract int getBalas();

	/**
	 * Consulta el estado del pincel
	 *
	 * @return true, si el pincel esta activado, false en caso contrario.
	 */
	public boolean getPincel() {
		return pincel;
	}

	/**
	 * Cambia el estado del pincel
	 *
	 * @param pincel nuevo estado del pincel
	 */
	public void setPincel(boolean pincel) {
		this.pincel = pincel;
	}

	/**
	 * Cambia el colo del pincel.
	 *
	 * @param c el nuevo color.
	 */
	public void setColor(String c) {
		color = c;
	}

	/**
	 * Devuelve un iterador de los Coleccionables en el baul del robot.
	 *
	 * @return un iterador de los coleccionables en el baul del robot.
	 */
	public Iterator<Coleccionable> getBaul(){
		return baul.iterator();
	}

	/**
	 * Vacia el baul del robot.
	 */
	public void vaciarBaul(){
		baul.clear();
	}

}
